package agent;

import common.DominoState;
import common.Move;
import common.Piece;
import common.Side;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

/**
 * Represents a fictitious state with the agent pieces and the "guessed"
 * opponent pieces (and other things). It is used by the alpha-beta algorithm
 * during the search process. Sugestions: - Define an attribute that indicates
 * which player plays in this state. - When the successors of a state are
 * generated (getSuccessors), you should determine for each successor what is
 * the player which plays in that state. This information is needed so that
 * alpha-beta algorithm can decide, for each succesor, if it calls maxValue or
 * minValue. - Override method isValidMove because, if not, all moves are
 * considered valid because the list of played pieces is not used in the search
 * process and is always empty (see the isValidMove method in class
 * DominoState). Notice that, during the search process you don't need to use
 * the already list of played pieces (defined in class DominoState), so, it is
 * always empty. You just need to know what are the left and right values in the
 * extremities of the already played pieces (also defined in class DominoState).
 * - You should not use the placePiece method as it is implemented in class
 * AgentCurrentState because it was conceived for the "real" state that the
 * agent knows (for example, it doesn't remove opponent pieces when it plays).
 * You should implement another method (maybe with the same name) that places a
 * piece and makes the necessary modifications, namely, it should remove a piece
 * from the playing player, create the Move describing the... move and determine
 * the next player to play. - You should, obviously, implement methods
 * getSuccessors, utility and evaluate and isEndOfGameState. - Other aspects you
 * may consider necessary.
 */
public class AgentSearchState extends AgentState {

    //Attributes...
    private Player player;
    private Move move;
    protected double sumMinMaxValue;

    public AgentSearchState() {
        sumMinMaxValue = 0;
    }
//    When the successors of a state are generated (getSuccessors), you should
// *   determine for each successor what is the player which plays in that state.
// *   This information is needed so that alpha-beta algorithm can decide, for each
// *   succesor, if it calls maxValue or minValue.

    public List<AgentSearchState> getSucessors() {
        List<AgentSearchState> sucessorsList = new LinkedList<>();
        System.out.println(player);
        if (player == Player.AGENT) {
            for (Piece agentPiece : agentPieces) {
                AgentSearchState sucessor;
                if (isValidMove(Side.LEFT, agentPiece)) {
                    sucessor = (AgentSearchState) clone();
                    sucessor.placePiece(player, Side.LEFT, agentPiece, sucessor);
                    sucessorsList.add(sucessor);
                }
                if (isValidMove(Side.RIGHT, agentPiece)) {
                    sucessor = (AgentSearchState) clone();
                    sucessor.placePiece(player, Side.RIGHT, agentPiece, sucessor);
                    sucessorsList.add(sucessor);
                }
            }
        } else if (player == Player.OPPONENT) {
        }
        return sucessorsList;
    }

    @Override
    public boolean isValidMove(Side side, Piece piece) {
        return side == Side.LEFT && piece.hasValue(leftValue) || side == Side.RIGHT && piece.hasValue(rightValue);
    }

// * - You should not use the placePiece method as it is implemented in class
// * AgentCurrentState because it was conceived for the "real" state that the
// * agent knows (for example, it doesn't remove opponent pieces when it plays).
// * You should implement another method (maybe with the same name) that places a
// * piece and makes the necessary modifications, namely, it should remove a piece
// * from the playing player, create the Move describing the... move and determine
// * the next player to play.    
    public boolean placePiece(Player player, Side side, Piece piece, AgentSearchState sucessor) {
        if (side == Side.LEFT) {
            byte outsideValue = piece.getOppositeValue(leftValue);
            sucessor.leftValue = outsideValue;
            sucessor.playedPieces.addFirst(piece);
        } else {
            byte outsideValue = piece.getOppositeValue(rightValue);
            sucessor.rightValue = outsideValue;
            sucessor.playedPieces.addLast(piece);
        }
        if (player == Player.AGENT) {
            sucessor.agentPieces.remove(piece);
            sucessor.move = new Move(side, piece);
            sucessor.player = Player.OPPONENT;
            return true;
        } else if (player == Player.OPPONENT) {

            sucessor.player = Player.AGENT;
        }

        return false;
    }

    //Maybe you need at least one more constructor...
    //construtor a receber um agentcurrentstate
    //...
    public AgentSearchState(AgentCurrentState agentCurrentState) {

    }

    public AgentSearchState(LinkedList<Piece> agentPieces, LinkedList<Piece> opponentPieces, byte leftValue, byte rightValue, Player player) {

    }

    public boolean isEndOfGameState() {
        return agentPieces.isEmpty() || opponentPossiblePieces.isEmpty() || !agentCanPlay() || !opponentCanPlay();
    }

    public double evaluate() {

        return (getAllDots() - getAllDotsAgent()) - (getAllDots() - getAllDotsOpponent());
    }

    // Maybe you need to override the clone method...
    @Override
    public Object clone() {
        AgentSearchState c = new AgentSearchState();
        c.agentPieces = agentPieces;
        c.allPieces = new Piece[PIECE_SET_SIZE];
        int count = 0;
        for (byte i = 0; i <= DOMINO_ORDER; i++) {
            for (byte j = i; j <= DOMINO_ORDER; j++) {
                c.allPieces[count] = allPieces[count];
                count++;
            }
        }
        c.leftValue = leftValue;
        c.rightValue = rightValue;
        c.player = player;
        c.playedPieces = new LinkedList<>(playedPieces);
        return c;
    }

    public Move getMove() {
        return move;
    }

    public Player getPlayer() {
        return player;
    }

    public boolean agentCanPlay() {
        boolean b = false;
        for (Piece p : agentPieces) {
            if (p.getValue1() == leftValue || p.getValue1() == rightValue || p.getValue2() == leftValue || p.getValue2() == rightValue) {
                b = true;
            }
        }
        return b;
    }
    //TODO
     public boolean opponentCanPlay() {
        boolean b = false;
        for (Piece p : opponentPossiblePieces) {
            if (p.getValue1() == leftValue || p.getValue1() == rightValue || p.getValue2() == leftValue || p.getValue2() == rightValue) {
                b = true;
            }
        }
        return b;
    }

}
